package com.jumper.study.front.service.impl;

import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.toolkit.SqlHelper;
import com.jumper.study.admin.service.StudentLessonService;
import com.jumper.study.common.api.OrderStatusCode;
import com.jumper.study.common.api.ResultCode;
import com.jumper.study.common.exception.ApiException;
import com.jumper.study.common.exception.Asserts;
import com.jumper.study.common.util.OrderNoUtil;
import com.jumper.study.db.dao.LessonMapper;
import com.jumper.study.db.dao.OrderMapper;
import com.jumper.study.db.dto.OrderDto;
import com.jumper.study.db.dto.OrderSearchDto;
import com.jumper.study.db.model.Lesson;
import com.jumper.study.db.model.Order;
import com.jumper.study.db.model.StudentLesson;
import com.jumper.study.front.dto.req.OrderCreateReq;
import com.jumper.study.front.dto.req.OrderSearchReq;
import com.jumper.study.front.dto.resp.OrderDetailResp;
import com.jumper.study.front.dto.resp.OrderItemResp;
import com.jumper.study.front.dto.vo.PageVO;
import com.jumper.study.front.service.OrderService;

@Service("frontOrderService")
public class OrderServiceImpl implements OrderService {
    @Autowired
    private OrderMapper orderMapper;

    @Autowired
    private LessonMapper lessonMapper;

    @Autowired
    private StudentLessonService slService;

    @Override
    public List<OrderItemResp> pageSearchList(PageVO page, OrderSearchReq search) {
        Page<OrderDto> p = Page.of(page.getPage(), page.getPageSize());
        OrderSearchDto dto = new OrderSearchDto();
        dto.setAccountId(search.getAccountId());
        dto.setStatus(search.getStatus());
        List<OrderDto> orders = orderMapper.pageSearchWithLesson(p, dto).getRecords();
        page.setTotal(p.getTotal());

        return orders.stream().map(o -> {
            OrderItemResp item = new OrderItemResp();
            item.setId(o.getId());
            item.setLessonId(o.getLessonId());
            item.setOrderNo(o.getOrderNo());
            item.setPrice(o.getPrice());
            item.setStatus(o.getStatus());
            item.setThumb(o.getLessonThumb());
            item.setTitle(o.getLessonTitle());
            item.setCreatedAt(o.getCreatedAt());
            return item;
        }).toList();
    }

    @Override
    public OrderDetailResp detail(Long id, Long accountId) {
        return detail(getById(id, accountId));
    }

    @Override
    public OrderDetailResp detail(String orderNo, Long accountId) {
        return detail(getByOrderno(orderNo, accountId));
    }

    private OrderDetailResp detail(Order order) {
        LambdaQueryWrapper<Lesson> query = Wrappers.lambdaQuery();
        query.select(Lesson::getId, Lesson::getTitle, Lesson::getThumb);
        query.eq(Lesson::getId, order.getLessonId());
        Lesson lesson = lessonMapper.selectOne(query);

        OrderDetailResp detail = new OrderDetailResp();
        detail.setId(order.getId());
        detail.setLessonId(order.getLessonId());
        detail.setOrderNo(order.getOrderNo());
        detail.setPrice(order.getPrice());
        detail.setStatus(order.getStatus());
        detail.setTitle("");
        detail.setThumb("");
        detail.setCreatedAt(order.getCreatedAt());
        if (lesson != null) {
            detail.setTitle(lesson.getTitle());
            detail.setThumb(lesson.getThumb());
        }

        return detail;
    }

    @Override
    public String create(OrderCreateReq data) throws ApiException {
        Order order = new Order();
        order.setAccountId(data.getAccountId());
        order.setLessonId(data.getLessonId());
        order.setPrice(data.getPrice());
        order.setStatus(OrderStatusCode.UNPAY);
        order.setOrderNo(OrderNoUtil.generate());
        int ret = orderMapper.insert(order);
        if (ret >= 0) {
            return order.getOrderNo();
        }

        Asserts.fail("下单失败");
        return null;
    }

    @Override
    public boolean cancel(Long id, Long accountId) {
        return cancel(getById(id, accountId));
    }

    @Override
    public boolean cancel(String orderNo, Long accountId) {
        return cancel(getByOrderno(orderNo, accountId));
    }

    private boolean cancel(Order order) {
        if (order.canCanceled()) {
            LambdaUpdateWrapper<Order> updateWrapper = Wrappers.lambdaUpdate();
            updateWrapper.set(Order::getStatus, OrderStatusCode.CANCELED);
            updateWrapper.eq(Order::getId, order.getId());
            int ret = orderMapper.update(updateWrapper);
            return SqlHelper.retBool(ret);
        }
        return false;
    }

    @Override
    public boolean payed(Long id, Long accountId) {
        return payed(getById(id, accountId));
    }

    @Override
    public boolean payed(String orderNo, Long accountId) {
        return payed(getByOrderno(orderNo, accountId));
    }

    //支付完成，开通课程
    @Transactional
    private boolean payed(Order order) {
        if (order.canPay()) {
            LambdaUpdateWrapper<Order> updateWrapper = Wrappers.lambdaUpdate();
            updateWrapper.set(Order::getStatus, OrderStatusCode.COMPLETE);
            updateWrapper.eq(Order::getId, order.getId());
            int ret = orderMapper.update(updateWrapper);
            if (ret <= 0) {
                Asserts.fail("支付变更失败");
            }
            StudentLesson sl = new StudentLesson();
            sl.setAccountId(order.getAccountId());
            sl.setAdminId(0l);
            sl.setLessonId(order.getLessonId());
            sl.setOrderId(order.getId());
            sl.setStudyTimes(0l);
            boolean result = slService.openLesson(sl);
            if (!result) {
                Asserts.fail("课程开通失败");
            }
            return true;
        }
        return false;
    }
    
    private Order getById(Long id, Long accountId) {
        Order order = orderMapper.selectById(id);
        if (order == null || accountId != order.getAccountId()) {
            Asserts.fail(ResultCode.NOT_FOUND.getCode(), "订单不存在");
        }

        return order;
    }

    private Order getByOrderno(String orderNo, Long accountId) {
        LambdaQueryWrapper<Order> query = Wrappers.lambdaQuery();
        query.eq(Order::getOrderNo, orderNo);
        Order order = orderMapper.selectOne(query);
        if (order == null || accountId != order.getAccountId()) {
            Asserts.fail(ResultCode.NOT_FOUND.getCode(), "订单不存在");
        }
        return order;
    }
}
